﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Input;
using AzureTracer.Model;
using AzureTracer.Resources;
using AzureTracer.Services;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Microsoft.Phone.Controls;
using GalaSoft.MvvmLight.Messaging;
using System.Windows.Navigation;
using System.Windows.Controls;
using System.Windows;
using GalaSoft.MvvmLight.Ioc;
using System.Text;
using AzureTracer.Common;
using System.Threading;

namespace AzureTracer.ViewModels
{
    public class MainViewModel : ViewModelBase
    {
        #region Private Variables
        private ILogService _logService;
        private INavigationService _navigationService;
        private IAppSettings _appSettings;
        private IEmailService _emailService;
        
        private CollectionViewSource _allLogs;
        private CollectionViewSource _errorLogs;
        private CollectionViewSource _warningLogs;
        private CollectionViewSource _infoLogs;
      
        private string _actualPivotName;
        private DateTime _lastSyncShowMessage;
        #endregion

        #region Properties
        public CollectionViewSource AllLogs { get { return _allLogs; } }
        public CollectionViewSource ErrorLogs { get { return _errorLogs; } }
        public CollectionViewSource WarningLogs { get { return _warningLogs; } }
        public CollectionViewSource InfoLogs { get { return _infoLogs; } }
        public ProgressIndicatorViewModel StateInfo { get; private set; }   
        public IAppSettings AppSettings { get { return _appSettings ; } }
        #endregion

        #region SearchText Property
        private string _searchText;
        public string SearchText
        {
            get
            { return _searchText; }
            private set
            {
                if (_searchText == value) return;
                _searchText = value;
                RaisePropertyChanged("SearchText");
            }
        } 
        #endregion

        #region SearchActive NotifyProperty
        private bool _searchActive;
        public bool SearchActive
        {
            get { return _searchActive; }
            set
            {
                if (_searchActive != value)
                {
                    _searchActive = value;
                    RaisePropertyChanged("SearchActive");
                }
            }
        }
        #endregion
     
        #region Commands
        public ICommand RefreshCommnad { get; private set; }
        public ICommand SearchCommand { get; private set; }
        public ICommand ShowSearchCommand { get; private set; }
        public ICommand LoadedCommand { get; private set; }
        public ICommand AllAsReadCommand { get; private set; }
        public ICommand ConfigurationCommand { get; private set; }

        public RelayCommand<SelectionChangedEventArgs> PivotSelectionChanged { get; private set; }

        public RelayCommand<List<object>> SendEmailMultipleCommand { get; private set; }
        public RelayCommand<List<object>> DeleteMultipleCommand { get; private set; }
        public RelayCommand<List<object>> SetAsReadMultipleCommand { get; private set; }
        public RelayCommand<List<object>> SetAsUnreadMultipleCommand { get; private set; }

        public RelayCommand<LogEntity> DeleteCommand { get; private set; }
        public RelayCommand<LogEntity> SelectCommand { get; private set; }
        public RelayCommand<LogEntity> SetAsReadCommand { get; private set; }
        public RelayCommand<LogEntity> SetAsUnreadCommand { get; private set; }
        #endregion

        public MainViewModel()
            :this(ViewModelLocator.AppSettings,ViewModelLocator.LogService,ViewModelLocator.NavigationService,ViewModelLocator.EmailService) {}
        
        [PreferredConstructor]
        public MainViewModel(IAppSettings appSettings, ILogService logService, INavigationService navigationService, IEmailService emailService)
        {
            _appSettings = appSettings;
            _logService = logService;
            _navigationService = navigationService;
            _emailService = emailService;
           
            _actualPivotName = labels.All;
            _lastSyncShowMessage = DateTime.Now.AddHours(-1);

            SearchText = string.Empty;
            StateInfo = new ProgressIndicatorViewModel();

            InitializeCollectionViewSources();

            LoadedCommand = new RelayCommand(OnLoaded);
            RefreshCommnad = new RelayCommand(OnRefresh);
            SearchCommand = new RelayCommand<string>(OnSearch);
            ShowSearchCommand = new RelayCommand(() => SearchActive = true);
            AllAsReadCommand = new RelayCommand(OnAllAsRead);
            ConfigurationCommand = new RelayCommand(OnGoToConfiguration);

            PivotSelectionChanged = new RelayCommand<SelectionChangedEventArgs>(OnPivotSelectionChanged);

            SendEmailMultipleCommand = new RelayCommand<List<object>>(OnSendEmailMultiple);
            DeleteMultipleCommand = new RelayCommand<List<object>>(OnDeleteMultiple);
            SetAsReadMultipleCommand = new RelayCommand<List<object>>(OnSetAsReadMultiple);
            SetAsUnreadMultipleCommand = new RelayCommand<List<object>>(OnSetAsUnreadMultiple);

            SelectCommand = new RelayCommand<LogEntity>(OnSelect);
            DeleteCommand = new RelayCommand<LogEntity>(OnDelete);
            SetAsReadCommand = new RelayCommand<LogEntity>(OnSetAsRead);
            SetAsUnreadCommand = new RelayCommand<LogEntity>(OnSetAsUnread);

            Messenger.Default.Register<bool>(this, SearchViewModel.ISSEARCHING_MESSAGE, OnIsSearchingChanged);
        }

        #region Commands Events
        private void OnPivotSelectionChanged(SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count == 0) return;

            PivotItem pivotItem = e.AddedItems[0] as PivotItem;
            _actualPivotName = pivotItem.Header.ToString();
        }
        
        private void OnIsSearchingChanged(bool isSearching)
        {
            if (isSearching)
                StateInfo.StartLoading(labels.Searching);
            else
                StateInfo.EndLoading();
        }

        private void OnAllAsRead()
        {
            CollectionViewSource actualViewSource;

            if (_actualPivotName == labels.Error)
                actualViewSource = _errorLogs;
            else if (_actualPivotName == labels.Warning)
                actualViewSource = _warningLogs;
            else if (_actualPivotName == labels.Info)
                actualViewSource = _infoLogs;
            else
                actualViewSource = _allLogs;

            foreach (var log in actualViewSource.View)
                ((LogEntity)log).IsRead = true;
        }

        private void OnGoToConfiguration()
        {
            _navigationService.ToConfiguration();
        }

        private void OnLoaded()
        {
            if (_appSettings.AccountName == string.Empty)
            {
                _navigationService.ToLogin();
            }
            else
            {
                if (_appSettings.ReadyToSync())
                    OnRefresh();
                else
                {
                    if (DateTime.Now > _lastSyncShowMessage.AddMinutes(1))
                    {
                        string mesage = string.Format(labels.LastSync, RelativeTimeConverter(_appSettings.LastTimeSync));
                        StateInfo.ShowMessage(mesage);
                        _lastSyncShowMessage = DateTime.Now;
                    }
                }
            }
        }

        private void OnRefresh()
        {
            if (!StateInfo.IsLoading)
            {
                StateInfo.StartLoading(labels.Synchronizing);
                _logService.LoadData(OnRefreshCompleted);
            }
        }

        private void OnRefreshCompleted(int count, Exception error)
        {
            string stateStr = (error == null) ?
                string.Format(labels.SyncCompleted, count) :
                ResourceHelper.SyncExceptionMessage(error);
            
            // Running on the UI thread.   
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                StateInfo.ShowMessage(stateStr);
            });
        }

        private void OnSendEmailMultiple(List<object> logsToSendEmail)
        {
            int cnt = 0;
            StringBuilder body = new StringBuilder();
            foreach (LogEntity Log in logsToSendEmail)
            {
                cnt++;
                body.AppendFormat("\r\n- Log {0}/{1} ---\r\n", cnt, logsToSendEmail.Count);
                body.AppendFormat(labels.EmailBody
                    , Log.Timestamp, Log.Role, Log.RoleInstance, Log.Message);
                body.AppendFormat("\r\n");
            }

            string subjet = labels.EmailMultipleSubjet;

            _emailService.SendToUnknow(subjet, body.ToString());
        }

        private void OnDeleteMultiple(List<object> logsToDelete)
        {
            foreach (var item in logsToDelete)
                OnDelete(item as LogEntity);
        }

        private void OnSetAsReadMultiple(List<object> logsToRead)
        {
            foreach (var item in logsToRead)
                OnSetAsRead(item as LogEntity);
        }

        private void OnSetAsUnreadMultiple(List<object> logsToUnread)
        {
            foreach (var item in logsToUnread)
                OnSetAsUnread(item as LogEntity);
        }

        private void OnSelect(LogEntity log)
        {
            if (log != null)
                _navigationService.ToDetail(log);
        }

        private void OnSetAsRead(LogEntity item) { item.IsRead = true; }

        private void OnSetAsUnread(LogEntity item) { item.IsRead = false; }

        private void OnSearch(string searchText)
        {
            SearchText = searchText.ToLowerInvariant();

            _allLogs.View.Refresh();
            _errorLogs.View.Refresh();
            _infoLogs.View.Refresh();
            _warningLogs.View.Refresh();
        }
        
        private void OnDelete(LogEntity item)
        {
            _logService.LogList.Remove(item);
        }
        #endregion

        private void InitializeCollectionViewSources()
        {
            var eventTickSortDescription = new SortDescription("EventTickCount", ListSortDirection.Descending);
            _allLogs = new CollectionViewSource();
            _allLogs.Source = _logService.LogList;
            _allLogs.SortDescriptions.Add(eventTickSortDescription);            

            _infoLogs = new CollectionViewSource();
            _infoLogs.Source = _logService.LogList;
            _infoLogs.SortDescriptions.Add(eventTickSortDescription);

            _warningLogs = new CollectionViewSource();
            _warningLogs.Source = _logService.LogList;
            _warningLogs.SortDescriptions.Add(eventTickSortDescription);

            _errorLogs = new CollectionViewSource();
            _errorLogs.Source = _logService.LogList;
            _errorLogs.SortDescriptions.Add(eventTickSortDescription);

            _allLogs.View.Filter = (e) =>
            {
                if (SearchText == string.Empty) return true;
                LogEntity item = (LogEntity)e;
                return item.LowerMessage.Contains(SearchText);
            };

            _errorLogs.View.Filter = (e) =>
            {
                LogEntity item = (LogEntity)e;
                if (item.Level != 2) return false;
                if (SearchText == string.Empty) return true;
                return item.LowerMessage.Contains(SearchText);
            };
            _warningLogs.View.Filter = (e) =>
            {
                LogEntity item = (LogEntity)e;
                if (item.Level != 3) return false;
                if (SearchText == string.Empty) return true;
                return item.LowerMessage.Contains(SearchText);
            };
            _infoLogs.View.Filter = (e) =>
            {
                LogEntity item = (LogEntity)e;
                if (item.Level != 4) return false;
                if (SearchText == string.Empty) return true;
                return item.LowerMessage.Contains(SearchText);
            };
        }

        private string RelativeTimeConverter(DateTime date)
        {
            try
            {
                RelativeTimeConverter converter = new RelativeTimeConverter();
                return converter.Convert(date, null, null, CultureInfo.CurrentCulture) as string;
            }
            catch (Exception)
            {
                return labels.unknow;
            }
            
        }
    }
}